/**
   forest.cuh - Created by Timothy Morey on 1/25/2012.
*/

#ifndef __FOREST_CUH
#define __FOREST_CUH

#include <curand_kernel.h>

#define MAX_THREADS_PER_BLOCK 32

#define FIRE 0x000000FF

#define GROWTH_CHANNEL 0x0000FF00
#define GROWTH_BUMP 0x00000100

#define GRASS_MIN 1
#define GRASS_MAX 40
#define TREE_MIN 41
#define TREE_MAX 255

/**
   When a cell contains bare ground, the GROUND_GROWTH_PROB gives the probability
   that something will start growing there in a given time step.
 */
#define GROUND_GROWTH_PROB 0.001

/**
   When a cell contains grass, and it is not on fire, the GRASS_GROWTH_PROB
   gives the probability that more growth will occur at a given time step.
*/
#define GRASS_GROWTH_PROB 0.01

/**
   When a cell contains trees, and it is not on fire, the TREE_GROWTH_PROB gives
   the probability that more growth will occur at a given time step.
*/
#define TREE_GROWTH_PROB 0.005

/**
   When a cell has burning neighbors, the probability that the fire will spread
   into the cell is the FIRE_SPREAD_PROB multiplied by the number of burning 
   neighbors.
 */
#define FIRE_SPREAD_PROB 0.0015

/**
   The RANDOM_SPARK_PROB gives the probability that a cell will spontaneously
   combust at any time step.
 */
#define RANDOM_SPARK_PROB 1e-7


////////////////////////////////////////////////////////////////////////////////
// CUDA Kernels:

__global__
void Downsample(unsigned int* forest, char* forestImg, 
								unsigned short width, unsigned short height);

/**
   Initializes the forest grid with random growth.

   @todo Describe the block/thread orgnization.

   @param grid An array representation of the forest in row-major order.  The
   length of the array is assumed to be width * height.
   @param rngStates An array of random number generator states, one of which is
   reserved for each thread executing this kernel.
   @param width The width of the forest in cells, or the number of columns in 
   the forest grid.
   @param height The height of the forest in cells, or the number of rows in
   the forest grid.
 */
__global__
void InitForest(unsigned int *grid, curandState* rngStates,
								unsigned short width, unsigned short height);

/**
   Initializes an array of random number generators that may be called from
   device code.  This kernel must be run before any kernel that needs random
   numbers.  One random number generator (one curandState) should be prepared
   for each thread that will require random numbers.

   @todo Describe the block/thread organization.

   @param rngStates An array of random number generator states that will be
   initialized by this kernel.
   @param seed A seed value that guarantess that the random number generators
   will be different than the last ones that were initialized.
 */
__global__
void InitRNG(curandState* rngStates, int seed);

__global__
void Step(unsigned int *curGrid, unsigned int *newGrid, 
					curandState* rngStates,
					unsigned short width, unsigned short height);


////////////////////////////////////////////////////////////////////////////////
// Device Helper Functions:

__device__
__host__
void Burn(unsigned int& cellValue);

__device__
__host__
void Extinguish(unsigned int& cellValue);

__device__
__host__
void FillLocalRegion(unsigned int* grid, unsigned short width, unsigned short height,
		     unsigned short row, unsigned short col, unsigned int* localRegion);

__device__
bool FlipCoin(float probability, curandState& rngState);

__device__
__host__
int GetForestIndex(int row, int width, int col);

__device__
__host__
unsigned char GetGrowth(unsigned int cellValue);

__device__
void Grow(unsigned int& cellValue, curandState& rngState);

__device__
__host__
void Ignite(unsigned int& cellValue);

__device__
__host__
bool IsBurning(unsigned int cellValue);

__device__
__host__
bool IsGround(unsigned int cellValue);

__device__
__host__
bool IsGrass(unsigned int cellValue);

__device__
__host__
bool IsTrees(unsigned int cellValue);

__device__
unsigned char RandomByte(curandState& rngState);

__device__
float RandomFloat(curandState& rngState);

__device__
unsigned int RandomInt(curandState& rngState);

#endif
